struct Cacher<T>
    where T: Fn(u32) -> u32
    {
        calculation: T,
        value: Option<u32>,
    }

impl<T> Cacher<T>
    where T: Fn(u32) -> u32
    {
        fn new(calculation:T) -> Cacher<T> {
            Cacher {
                calculation,
                value: None
            }
        }
        fn value(&mut self, arg: u32) -> u32 {
            match self.value {
                Some(v) => v,
                None => {
                    // self.calculation为何要用括号括起来?
                    // 因为self.calculation是一个闭包, 闭包是一个trait对象, 需要调用它的方法, 需要使用括号
                    let v = (self.calculation)(arg);
                    self.value = Some(v);
                    // 这里为何要返回v?
                    // 因为闭包的返回值是u32, 所以这里需要返回一个u32
                    v
                }
            }
        }
    }

fn main() {
    // 这里为何要使用mut?
    // 因为Cacher是一个结构体, 结构体是值类型, 后续操作又会改变它的值, 所以需要使用mut
    let mut cacher = Cacher::new(|x| x);
    // 这样做的好处就是, 无论value方法调用几次,闭包只执行一次!
    let result = cacher.value(3);
    let result2 = cacher.value(3);
    println!("result:{}", result);
    print!("result2:{}", result2);
    // 13.4
    // 闭包可以捕获环境里的变量, 而函数则不能
    let y = 12;
    let closure = |x| x + y;
    println!("closure:{}", closure(1));
    // 如果是函数则会报错
    // fn test_fn () {
    //     // 此处会报错, 因为函数不能捕获环境里的变量
    //     let closure = |x| x + y;
    //     println!("closure:{}", closure(1));
    // }
    // FnOnce会获得闭包的所有权, FnMut会捕获环境中的可变引用, Fn会捕获环境中的不可变引用
    // rust会根据我们的使用方式来推断闭包的类型
    // 所有闭包都实现了FnOnce trait, 但是只有那些完全获取了其所有权的闭包才实现了FnMut trait, 
    // 而那些既没有获取所有权也不能被可变借用的闭包则实现了Fn trait
    // move关键字可以强制闭包获取其环境的所有权
    let mut vec1 = vec![1, 2, 3];
    let mut clouse_mut = move |x| vec1.push(x);
    clouse_mut(4);
    // 此处会报错, 因为clouse_mut已经获取了vec1的所有权, 所以不能再使用vec1
    // println!("vec1: {:?}", vec1);
}

/*
 * rust的闭包至少要实现一以下三种trait之一: Fn, FnMut, FnOnce
 */
